/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#import "AWSafeAreaMonitor.h"
#import <objc/runtime.h>
#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

// 状态栏
const int SAFE_AREA_TYPE_STATUSBAR = 0;
// 刘海
const int SAFE_AREA_TYPE_NOTCH = 1;
// 手势
const int SAFE_AREA_TYPE_GESTURE = 2;
// 键盘
const int SAFE_AREA_TYPE_KEYBOARD = 3;
// 底部导航栏
const int SAFE_AREA_TYPE_NAVIGATIONTOOLBAR = 4;

@interface AWSafeAreaMonitor ()
@property(nonatomic, weak) UIWindow *targetWindow;
@property(nonatomic, copy) SafeAreaUpdateHandler updateHandler;
@property(nonatomic, assign) BOOL isKeyboardVisible;
@property(nonatomic, assign) CGRect keyboardFrame;
@property(nonatomic, assign) BOOL hasAddedSafeAreaObserver;
@property(nonatomic, assign) BOOL hasKeyboardObserver;
@property(nonatomic, assign) UIInterfaceOrientation lastKnownOrientation;
@property(nonatomic, assign) UIEdgeInsets lastInsets;

@end

@implementation AWSafeAreaMonitor

+ (instancetype)shared
{
    static AWSafeAreaMonitor *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
      instance = [[AWSafeAreaMonitor alloc] init];
    });
    return instance;
}

- (void)addAvoidAreaListener:(SafeAreaUpdateHandler)handler
{
    self.updateHandler = handler;
    self.targetWindow = [self currentKeyWindow];
    self.lastKnownOrientation = [self currentInterfaceOrientation];

    // 安全区域变化通知
    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(handleSafeAreaChange)
                                               name:UIDeviceOrientationDidChangeNotification
                                             object:nil];

    // 监听横竖屏幕切换
    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(handleInterfaceOrientationChange)
                                               name:UIApplicationDidChangeStatusBarOrientationNotification
                                             object:nil];

    // 键盘事件监听
    if (!self.hasKeyboardObserver) {
        [self cancelKeyboardFrameObserver];
        [self addKeyboardFrameObserver];
    }
    // 动态添加安全区域监听
    [self addSafeAreaObserver];
}

- (void)removeAvoidAreaListener
{
    [NSNotificationCenter.defaultCenter removeObserver:self];
    [self removeSafeAreaObserver];
    self.updateHandler = nil;
}

#pragma mark - 核心计算逻辑
- (void)calculateCurrentSafeAreas
{

    NSMutableDictionary *areas = [NSMutableDictionary dictionary];

    // 状态栏
    CGRect statusBarFrame = [self calculateStatusBarRect];
    areas[@(SAFE_AREA_TYPE_STATUSBAR)] = [NSValue valueWithCGRect:statusBarFrame];

    // 刘海屏/挖孔屏
    CGRect notchRect = [self calculateNotchAreaRect];
    areas[@(SAFE_AREA_TYPE_NOTCH)] = [NSValue valueWithCGRect:notchRect];

    // 手势区域
    CGRect gestureRect = [self calculateGestureAreaRect];
    areas[@(SAFE_AREA_TYPE_GESTURE)] = [NSValue valueWithCGRect:gestureRect];

    // 键盘区域
    if (self.isKeyboardVisible) {
        areas[@(SAFE_AREA_TYPE_KEYBOARD)] = [NSValue valueWithCGRect:self.keyboardFrame];
    }

    // 底部导航栏
    CGRect toolbarRect = [self calculateNavigationToolbarFrame];
    areas[@(SAFE_AREA_TYPE_NAVIGATIONTOOLBAR)] = [NSValue valueWithCGRect:toolbarRect];

    // 对数据进行封装，返回字符串,单次回调
    [areas enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, NSValue *value, BOOL *stop) {
      CGRect rect = [value CGRectValue];
      NSDictionary *areaDict = @{
          @"type" : key,
          @"area" : [self buildAvoidAreaResultAuto:rect areaType:[key intValue]],
      };

      NSString *jsonString = @"";
      NSError *error = nil;
      NSData *jsonData = [NSJSONSerialization dataWithJSONObject:areaDict options:0 error:&error];
      if (error) {
          NSLog(@"❌ JSON 构建失败: %@", error);
      }
      jsonString = [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
      if (self.updateHandler) {
          self.updateHandler(jsonString);
      }
    }];
}

// 新增 CGRect 转 JSON 的工具方法
- (NSDictionary *)rectToDictionary:(CGRect)rect
{
    return @{
        @"left" : @(rect.origin.x),
        @"top" : @(rect.origin.y),
        @"width" : @(rect.size.width),
        @"height" : @(rect.size.height)
    };
}

- (NSDictionary *)buildAvoidAreaResultWithVisible:(BOOL)visible
                                         leftRect:(CGRect)leftRect
                                          topRect:(CGRect)topRect
                                        rightRect:(CGRect)rightRect
                                       bottomRect:(CGRect)bottomRect
{
    return @{
        @"visible" : @(visible),
        @"leftRect" : [self rectToDictionary:leftRect],
        @"topRect" : [self rectToDictionary:topRect],
        @"rightRect" : [self rectToDictionary:rightRect],
        @"bottomRect" : [self rectToDictionary:bottomRect]
    };
}
// pt 转 px
- (CGRect)convertPtRectToPx:(CGRect)ptRect
{
    CGFloat scale = [UIScreen mainScreen].scale;
    return CGRectMake(
        ptRect.origin.x * scale, ptRect.origin.y * scale, ptRect.size.width * scale, ptRect.size.height * scale);
}

// 构造避让区域数据结构
- (NSDictionary *)buildAvoidAreaResultAuto:(CGRect)rect areaType:(int)type
{
    UIWindow *window = [self currentKeyWindow];
    if (!window) {
        return @{};
    }
    // 每个方向构造 CGRect
    CGRect topRect = CGRectZero;
    CGRect bottomRect = CGRectZero;
    CGRect leftRect = CGRectZero;
    CGRect rightRect = CGRectZero;
    BOOL visible = NO;
    // 获取设备方向
    UIDeviceOrientation deviceOrientation = [[UIDevice currentDevice] orientation];
    NSInteger orientationValue = 0;
    switch (deviceOrientation) {
        case UIDeviceOrientationPortrait:
            orientationValue = 0;
            break;
        case UIDeviceOrientationLandscapeLeft:
            orientationValue = 1;
            break;
        case UIDeviceOrientationLandscapeRight:
            orientationValue = 2;
            break;
        case UIDeviceOrientationPortraitUpsideDown:
            orientationValue = 3;
            break;
        default:
            orientationValue = 0;
            break;
    }
    // pt转px
    rect = [self convertPtRectToPx:rect];

    if (type == SAFE_AREA_TYPE_STATUSBAR) {
        topRect = rect;
        visible = YES;
    } else if (type == SAFE_AREA_TYPE_NAVIGATIONTOOLBAR) {
        bottomRect = rect;
        visible = YES;
    } else {
        if (orientationValue == 0) {
            topRect = rect;
            visible = YES;
        } else if (orientationValue == 1) {
            leftRect = rect;
            visible = YES;
        } else if (orientationValue == 2) {
            rightRect = rect;
            visible = YES;
        } else if (orientationValue == 3) {
            bottomRect = rect;
            visible = YES;
        }
    }

    return [self buildAvoidAreaResultWithVisible:visible
                                        leftRect:leftRect
                                         topRect:topRect
                                       rightRect:rightRect
                                      bottomRect:bottomRect];
}

// 核心改造方法
- (NSString *)getWindowAvoidAreaForType:(int)type
{
    __block CGRect targetRect = CGRectZero;
    self.targetWindow = [self currentKeyWindow];
    switch (type) {
        case SAFE_AREA_TYPE_STATUSBAR: {
            targetRect = [self calculateStatusBarRect];
            break;
        }

        case SAFE_AREA_TYPE_NOTCH: {
            targetRect = [self calculateNotchAreaRect];
            break;
        }

        case SAFE_AREA_TYPE_GESTURE: {
            targetRect = [self calculateGestureAreaRect];
            break;
        }

        case SAFE_AREA_TYPE_KEYBOARD:
            if (!self.hasKeyboardObserver) {
                [self cancelKeyboardFrameObserver];
                [self addKeyboardFrameObserver];
            }
            targetRect = self.isKeyboardVisible ? self.keyboardFrame : CGRectZero;
            break;

        case SAFE_AREA_TYPE_NAVIGATIONTOOLBAR:
            targetRect = [self calculateNavigationToolbarFrame];
            break;

        default:
            break;
    }

    NSDictionary *result = [self buildAvoidAreaResultAuto:targetRect areaType:type];

    NSError *error;
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:result options:NSJSONWritingPrettyPrinted error:&error];

    return error ? @"" : [[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding];
}

// 判断是否在视图范围内
- (BOOL)isRectVisibleOnScreen:(CGRect)rect
{
    CGRect screenBounds = [UIScreen mainScreen].bounds;
    return CGRectIntersectsRect(screenBounds, rect);
}

// 获取底部导航栏位置
- (CGRect)calculateNavigationToolbarFrame
{
    UIWindow *window = [self currentKeyWindow];
    if (!window)
        return CGRectZero;
    CGRect bounds = [self transformedRectForOrientation:window.bounds];
    UIEdgeInsets insets = window.safeAreaInsets;
    if (insets.bottom <= 0)
        return CGRectZero;
    return CGRectMake(0, bounds.size.height - insets.bottom, bounds.size.width, insets.bottom);
}

// 获取状态栏位置
- (CGRect)calculateStatusBarRect
{
    UIWindow *window = [self currentKeyWindow];
    if (!window)
        return CGRectZero;

    CGFloat statusBarHeight = window.safeAreaInsets.top;
    CGFloat statusBarWidth = window.bounds.size.width;

    // 判断状态栏是否隐藏（iOS 13+）
    BOOL isStatusBarHidden = NO;
    if (@available(iOS 13.0, *)) {
        isStatusBarHidden = window.windowScene.statusBarManager.isStatusBarHidden;
    } else {
        isStatusBarHidden = [UIApplication sharedApplication].isStatusBarHidden;
    }

    // 条件：隐藏 or 宽或高为 0
    if (isStatusBarHidden || statusBarHeight <= 0 || statusBarWidth <= 0) {
        return CGRectZero;
    }

    return CGRectMake(0, 0, statusBarWidth, statusBarHeight);
}

// 获取刘海屏位置
- (CGRect)calculateNotchAreaRect
{
    UIWindow *window = [self currentKeyWindow];
    if (!window)
        return CGRectZero;

    // 确保窗口已布局
    UIEdgeInsets insets = window.safeAreaInsets;
    CGRect bounds = window.bounds;

    UIInterfaceOrientation orientation = UIInterfaceOrientationUnknown;
    if (@available(iOS 13.0, *)) {
        orientation = window.windowScene.interfaceOrientation;
    } else {
        orientation = [UIApplication sharedApplication].statusBarOrientation;
    }

    BOOL isiPhone = [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone;
    BOOL hasNotch = isiPhone && (insets.top >= 44 || insets.left > 0 || insets.right > 0);

    if (!hasNotch)
        return CGRectZero;
    if (UIInterfaceOrientationIsPortrait(orientation)) {
        return CGRectMake(0, 0, bounds.size.width, insets.top);
    }
    // 横屏时刘海在左或右，注意分别处理
    BOOL isPhysicalRight = NO;
    if (UIInterfaceOrientationIsLandscape(orientation)) {
        isPhysicalRight = orientation == UIInterfaceOrientationLandscapeLeft;
        if (insets.left >= 44) {
            if (isPhysicalRight) {
                // 刘海在右侧
                return CGRectMake(bounds.size.width - insets.right, 0, insets.right, bounds.size.height);
            } else {
                // 刘海在左侧
                return CGRectMake(0, 0, insets.left, bounds.size.height);
            }
        }
    }

    return CGRectZero;
}

// 获取手势位置
- (CGRect)calculateGestureAreaRect
{
    return CGRectZero;
}

// 新增坐标转换方法
- (CGRect)transformedStatusBarFrame:(CGRect)originalFrame orientation:(UIInterfaceOrientation)orientation
{
    if (UIInterfaceOrientationIsLandscape(orientation)) {
        return CGRectMake(0, 0, originalFrame.size.height, originalFrame.size.width);
    }
    return originalFrame;
}

// 增强坐标转换方法
- (CGRect)transformedRectForOrientation:(CGRect)originalRect
{
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

    if (UIInterfaceOrientationIsLandscape(orientation)) {
        return CGRectMake(
            originalRect.origin.y, originalRect.origin.x, originalRect.size.height, originalRect.size.width);
    }
    return originalRect;
}

#pragma mark - 键盘事件处理
- (void)keyboardFrameWillChange:(NSNotification *)notification
{
    NSDictionary *userInfo = notification.userInfo;
    UIWindow *window = [self currentKeyWindow];

    // 获取键盘动画持续时间
    NSTimeInterval duration = [userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue];

    // 获取动画曲线
    UIViewAnimationOptions options = [userInfo[UIKeyboardAnimationCurveUserInfoKey] integerValue] << 16;

    // 获取结束时键盘的 frame（以屏幕坐标为基准）
    CGRect endFrame = [userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue];

    // 转换为当前视图坐标系（很重要）
    CGRect keyboardFrameInView = [window convertRect:endFrame fromView:nil];

    // 键盘是否隐藏：Y 大于等于视图高度
    BOOL isKeyboardVisible = CGRectIntersectsRect(window.bounds, keyboardFrameInView);

    self.isKeyboardVisible = isKeyboardVisible;
    self.keyboardFrame = isKeyboardVisible ? keyboardFrameInView : CGRectZero;

    // 执行动画，更新布局
    [UIView animateWithDuration:duration
                          delay:0
                        options:options
                     animations:^{
                       [self calculateCurrentSafeAreas];  // 或者 layout 更新
                     }
                     completion:nil];
}

#pragma mark - 安全区域KVO监听
- (void)addSafeAreaObserver
{
    UIWindow *window = [self currentKeyWindow];
    if (self.hasAddedSafeAreaObserver && self.targetWindow == window) {
        return;
    }
    if (self.hasAddedSafeAreaObserver && self.targetWindow) {
        [self.targetWindow removeObserver:self forKeyPath:@"safeAreaInsets"];
    }

    self.targetWindow = window;
    if (self.targetWindow) {
        [self.targetWindow addObserver:self
                            forKeyPath:@"safeAreaInsets"
                               options:NSKeyValueObservingOptionNew
                               context:nil];
        self.hasAddedSafeAreaObserver = true;
    }
}

- (void)removeSafeAreaObserver
{
    if (!self.hasAddedSafeAreaObserver) {
        return;
    }

    UIWindow *window = [self currentKeyWindow];
    @try {
        [window removeObserver:self forKeyPath:@"safeAreaInsets"];
    } @catch (NSException *exception) {
        NSLog(@"⚠️ SafeAreaInsets 观察者移除失败: %@", exception.reason);
    }

    self.hasAddedSafeAreaObserver = NO;
    self.targetWindow = nil;
}

// 添加键盘监听
- (void)addKeyboardFrameObserver
{
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(keyboardFrameWillChange:)
                                                 name:UIKeyboardWillChangeFrameNotification
                                               object:nil];
    self.hasKeyboardObserver = YES;
}
// 取消键盘监听
- (void)cancelKeyboardFrameObserver
{
    [[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillChangeFrameNotification object:nil];
    self.hasKeyboardObserver = NO;
}

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
    if ([keyPath isEqualToString:@"safeAreaInsets"]) {
        UIEdgeInsets newInsets = [change[NSKeyValueChangeNewKey] UIEdgeInsetsValue];
        if (!UIEdgeInsetsEqualToEdgeInsets(self.lastInsets, newInsets)) {
            self.lastInsets = newInsets;
            [NSObject cancelPreviousPerformRequestsWithTarget:self
                                                     selector:@selector(calculateCurrentSafeAreas)
                                                       object:nil];
            [self performSelector:@selector(calculateCurrentSafeAreas) withObject:nil afterDelay:0.05];
        }
    }
}

#pragma mark - 方向变化处理
- (void)handleSafeAreaChange
{
    [self triggerSafeAreaUpdateIfNeeded];  // 合并处理逻辑
}

// 新增横竖屏切换处理方法
- (void)handleInterfaceOrientationChange
{
    NSLog(@"横竖屏切换了");
    [self triggerSafeAreaUpdateIfNeeded];
}
- (void)triggerSafeAreaUpdateIfNeeded
{
    UIInterfaceOrientation currentOrientation = [self currentInterfaceOrientation];

    // 避免重复处理
    if (self.lastKnownOrientation == currentOrientation) {
        return;
    }
    self.lastKnownOrientation = currentOrientation;

    // 延迟确保 layout 更新后再执行
    dispatch_async(dispatch_get_main_queue(), ^{
      self.targetWindow = [self currentKeyWindow];
      [self.targetWindow layoutIfNeeded];

      // 防抖处理，确保短时间内只执行一次
      [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(calculateCurrentSafeAreas) object:nil];
      [self performSelector:@selector(calculateCurrentSafeAreas) withObject:nil afterDelay:0.1];
    });
}

#pragma mark - 工具方法
- (UINavigationController *)topNavigationController
{
    UIViewController *rootVC = self.targetWindow.rootViewController;
    while (rootVC.presentedViewController) {
        rootVC = rootVC.presentedViewController;
    }

    if ([rootVC isKindOfClass:[UINavigationController class]]) {
        return (UINavigationController *)rootVC;
    } else if ([rootVC isKindOfClass:[UITabBarController class]]) {
        UIViewController *selectedVC = ((UITabBarController *)rootVC).selectedViewController;
        if ([selectedVC isKindOfClass:[UINavigationController class]]) {
            return (UINavigationController *)selectedVC;
        }
    }
    return nil;
}

- (UIWindow *)currentKeyWindow {
    // 尝试获取iOS 13+场景中的窗口
    UIWindow *foundWindow = [self findValidWindowInScenes];
    if (foundWindow) return foundWindow;

    // 尝试获取iOS 12及以下的keyWindow
    foundWindow = [self findValidKeyWindow];
    if (foundWindow) return foundWindow;

    // 尝试获取任意有效窗口
    foundWindow = [self findAnyValidWindow];
    if (foundWindow) return foundWindow;

    // 日志记录
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    NSLog(@"✅ currentKeyWindow = %@, frame = %@", window, NSStringFromCGRect(window.frame));
    NSLog(@"✅ safeAreaInsets = %@", NSStringFromUIEdgeInsets(window.safeAreaInsets));

    return window;
}
#pragma mark - Helper Methods
// 查找iOS 13+场景中的有效窗口
- (UIWindow *)findValidWindowInScenes {
    if (@available(iOS 13.0, *)) {
        for (UIScene *scene in [UIApplication sharedApplication].connectedScenes) {
            if (![self isActiveWindowScene:scene]) continue;

            UIWindowScene *windowScene = (UIWindowScene *)scene;
            UIWindow *window = [self findKeyWindowInScene:windowScene];
            if (window) return window;

            window = [self findFirstValidWindowInScene:windowScene];
            if (window) return window;
        }
    }
    return nil;
}
// 查找iOS 12及以下的keyWindow
- (UIWindow *)findValidKeyWindow {
    UIWindow *keyWindow = [UIApplication sharedApplication].keyWindow;
    return [self isValidWindow:keyWindow] ? keyWindow : nil;
}
// 查找任意有效窗口
- (UIWindow *)findAnyValidWindow {
    for (UIWindow *window in [UIApplication sharedApplication].windows) {
        if ([self isValidWindow:window]) {
            return window;
        }
    }
    return nil;
}
// 查找场景中的keyWindow
- (UIWindow *)findKeyWindowInScene:(UIWindowScene *)scene {
    for (UIWindow *window in scene.windows) {
        if (window.isKeyWindow && [self isValidWindow:window]) {
            return window;
        }
    }
    return nil;
}
// 查找场景中的第一个有效窗口
- (UIWindow *)findFirstValidWindowInScene:(UIWindowScene *)scene {
    for (UIWindow *window in scene.windows) {
        if ([self isValidWindow:window]) {
            return window;
        }
    }
    return nil;
}
// 检查是否是活跃的窗口场景
- (BOOL)isActiveWindowScene:(UIScene *)scene {
    return scene.activationState == UISceneActivationStateForegroundActive &&
           [scene isKindOfClass:[UIWindowScene class]];
}
// 检查窗口是否有效
- (BOOL)isValidWindow:(UIWindow *)window {
    return window && !window.hidden && window.alpha > 0 && CGRectGetWidth(window.frame) > 0;
}

- (UIInterfaceOrientation)currentInterfaceOrientation
{
    if (@available(iOS 13.0, *)) {
        NSSet *scenes = UIApplication.sharedApplication.connectedScenes;
        for (UIScene *scene in scenes) {
            if (scene.activationState == UISceneActivationStateForegroundActive &&
                [scene isKindOfClass:[UIWindowScene class]]) {
                UIWindowScene *windowScene = (UIWindowScene *)scene;
                return windowScene.interfaceOrientation;
            }
        }
        return UIInterfaceOrientationUnknown;
    } else {
        return UIApplication.sharedApplication.statusBarOrientation;
    }
}

@end